﻿using Orleans;
using Puppy.DependencyInjection;
using Puppy.Domain.Entities;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace Puppy.ActorDb
{
    public class ActorDatabase : IActorDatabase, ITransientDependency
    {
        private readonly ConcurrentDictionary<Type, object> _sets;

        private readonly ConcurrentDictionary<Type, ActorIdGenerator> _entityIdGenerators;

        private readonly IGrainFactory _grianFactory;

        public ActorDatabase(IGrainFactory grianFactory)
        {
            _sets = new ConcurrentDictionary<Type, object>();
            _entityIdGenerators = new ConcurrentDictionary<Type, ActorIdGenerator>();
            _grianFactory = grianFactory;
        }

        public IActorSet<TEntity> Collection<TEntity>()
            where TEntity : class, IEntity
        {
            var type = typeof(TEntity);
            return _sets.GetOrAdd(type,
                    _ => _grianFactory.GetGrain<IActorSet<TEntity>>(type.FullName)) as
                IActorSet<TEntity>;
        }

        public TKey GenerateNextId<TEntity, TKey>()
        {
            return _entityIdGenerators
                .GetOrAdd(typeof(TEntity), () => new ActorIdGenerator())
                .GenerateNext<TKey>();
        }
    }
}
